package me.jiatao.wan.paging3.home

import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import kotlinx.coroutines.delay
import me.jiatao.wan.common.ext.isConnectedNetwork
import me.jiatao.wan.data.database.AppDataBase
import me.jiatao.wan.data.database.entity.ArticleEntity
import me.jiatao.wan.data.database.entity.ArticleType
import me.jiatao.wan.data.mapper.ArticleMapper
import me.jiatao.wan.data.network.ApiException
import me.jiatao.wan.data.network.HttpConst
import me.jiatao.wan.data.network.api.WanAndroidApi
import me.jiatao.wan.data.network.apiDataCall
import me.jiatao.wan.data.network.pojo.ArticlePojo
import me.jiatao.wan.init.AppHelper
import timber.log.Timber

/**
 * @Author: JiaTao
 * @CreateDate: 2021/8/29 10:57
 * @Version: 1.0
 * @Description: 文章列表：主页、项目、公众号公用
 */

@ExperimentalPagingApi
class ArticleRemoteMediator(
    private val api: WanAndroidApi,
    private val db: AppDataBase,
    private val articleType: ArticleType,//文章分类
    private val cid: Int = 0//项目/公众号模块的类别标识
) : RemoteMediator<Int, ArticleEntity>() {

    /**
     * 数据库访问层
     */
    private val articleDao = db.articleDao()
    //private val remoteKeysDao = db.remoteKeysDao()

    /** 页面起始索引 */
    private val startPageIndex = 0

    /** 当前页面索引 */
    private var currentPageIndex = 0

    @ExperimentalPagingApi
    override suspend fun load(
        loadType: LoadType,
        state: PagingState<Int, ArticleEntity>
    ): MediatorResult {
        try {

            /**
             * 在这个方法内将会做三件事
             *
             * 1. 参数 LoadType 有个三个值，关于这三个值如何进行判断
             *      LoadType.REFRESH
             *      LoadType.PREPEND
             *      LoadType.APPEND
             *
             * 2. 访问网络数据
             *
             * 3. 将网路插入到本地数据库中
             */

            Timber.e("loadType = $loadType")

            /** 第一步：判断 LoadType */
            val pageKey = when (loadType) {
                // 首次访问 或者调用 PagingDataAdapter.refresh()
                LoadType.REFRESH -> startPageIndex

                // 在当前加载的数据集的开头加载数据时
                LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)

                // 加载更多时触发
                LoadType.APPEND -> {

                    /**
                     * 这里主要获取下一页数据的开始位置，可以理解为从什么地方开始加载下一页数据
                     * 这里有两种方式来获取下一页加载数据的位置
                     * 方式一：这种方式比较简单，当前页面最后一条数据是下一页的开始位置
                     * 方式二：比较麻烦，当前分页数据没有对应的远程 key，这个时候需要我们自己建表,
                     */

                    /**
                     * 方式一：这种方式比较简单，当前页面最后一条数据是下一页的开始位置
                     * 通过 load 方法的参数 state 获取当页面最后一条数据
                     */
                    val lastItem = state.lastItemOrNull()
                    if (lastItem == null) {
                        return MediatorResult.Success(endOfPaginationReached = false)
                    } else {
                        /** 这里由于服务器返回页码，所以可以直接使用 */
                        currentPageIndex
                    }

                    /**
                     * 方式二：比较麻烦，当前分页数据没有对应的远程 key，这个时候需要我们自己建表
                     */
                    //val remoteKey = db.withTransaction {
                    //    db.remoteKeysDao().getRemoteKeys(remotePokemon)
                    //}
                    //if (remoteKey == null || remoteKey.nextKey == null) {
                    //    return MediatorResult.Success(endOfPaginationReached = true)
                    //}
                    //remoteKey.nextKey
                }
            }

            if (!AppHelper.mContext.isConnectedNetwork()) {
                // 无网络加载本地数据
                return MediatorResult.Error(ApiException(HttpConst.CODE_NET_ERROR, HttpConst.MSG_NET_ERROR))
                //return MediatorResult.Success(endOfPaginationReached = true)
            }

            /** 第二步： 请求网络分页数据 */
            val result = getArticleEntityList(pageKey)
            val endOfPaginationReached = result.isEmpty()

            /** 第三步： 插入数据库 */
            db.withTransaction {
                if (loadType == LoadType.REFRESH) {
                    articleDao.clear(articleType)
                }

                /** 插入当前数据 */
                articleDao.insertList(result)


                // 方式二：存储远程Key
                // val nextKey = if (endOfPaginationReached) null else page + 1
                // val entity = RemoteKeysEntity(
                //     remoteName = remotePokemon,
                //     nextKey = nextKey
                // )
                // remoteKeysDao.insertAll(entity)
            }

            return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
        } catch (e: ApiException) {
            return MediatorResult.Error(e)
        }
    }

    /**
     * 根据文章类型获取文章列表
     */
    private suspend fun getArticleEntityList(page: Int): List<ArticleEntity> {
        return when (articleType) {
            ArticleType.HOME ->
                getHomeArticleList(page)
            ArticleType.PROJECT
            -> getProjectArticleList(page)
            ArticleType.WECHAT
            -> getHomeArticleList(page)
        }
    }

    /**
     * 获取主页数据
     */
    private suspend fun getHomeArticleList(page: Int): List<ArticleEntity> {
        val allArticleList = ArrayList<ArticlePojo>()

        /** 第一次获取置顶数据 */
        if (page == 0) {
            val topArticleList = apiDataCall {
                api.fetchTopArticleListApi()
            }
            allArticleList.addAll(topArticleList.map { item ->
                item.isTop = true
                item
            })
        }

        /** 主页数据 */
        val homeArticlePage = apiDataCall {
            api.fetchHomeArticleListApi(page)
        }

        /**
         * curPage自动返回下页索引
         */
        currentPageIndex = homeArticlePage.curPage

        val homeArticleList = homeArticlePage.articleList
        homeArticleList?.let {
            allArticleList.addAll(it)
        }

        return allArticleList.map { pojo ->
            ArticleMapper.articlePojo2Entity(pojo, ArticleType.HOME)
        }
    }

    /**
     * 获取项目模块文章列表
     */
    private suspend fun getProjectArticleList(page: Int): List<ArticleEntity> {
        /** 主页数据 */
        val articlePage = apiDataCall {
            api.fetchProjectArticleListApi(page, cid)
        }

        /**
         * curPage自动返回下页索引
         */
        currentPageIndex = articlePage.curPage

        if (articlePage.articleList == null) {
            throw ApiException(HttpConst.CODE_DATA_NULL, "data null")
        } else {
            return articlePage.articleList.map { pojo ->
                ArticleMapper.articlePojo2Entity(pojo, ArticleType.PROJECT)
            }
        }
    }
}